package net.xxcxcxcx.xc_enhancedmob.render.particle;

import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.option.ParticlesMode;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.render.Camera;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.util.math.Vec3d;
import net.xxcxcxcx.xc_enhancedmob.render.particle.custom.CustomBaseParticle;
import net.xxcxcxcx.xc_enhancedmob.render.particle.custom.CustomDirectionBaseParticle;
import net.xxcxcxcx.xc_enhancedmob.render.particle.summon.BaseSummonParticle;
import net.xxcxcxcx.xc_enhancedmob.render.particle.summon.CustomSummonParticle;
import net.xxcxcxcx.xc_enhancedmob.render.particle.summon.draw.DrawCircleSummonParticle;
import net.xxcxcxcx.xc_enhancedmob.render.particle.summon.magic.BaseSummonMagicParticle;
import net.xxcxcxcx.xc_enhancedmob.render.particle.summon.magic.circle.BaseAttackParticle;
import net.xxcxcxcx.xc_enhancedmob.render.particle.summon.magic.circle.BaseSummonMagicCircleParticle;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

@Environment(value = EnvType.CLIENT)
public class ParticleHelper {
    public static List<Class> customParticleList = new ArrayList<>();

    public static CustomSummonParticle MakeParticleForBuf(int num, PacketByteBuf buf) {
        if (num >= customParticleList.size()) return new BaseSummonParticle();
        Class aClass = customParticleList.get(num);
        try {
            Constructor constructor = aClass.getConstructor(PacketByteBuf.class);
            return (CustomSummonParticle) constructor.newInstance(buf);
        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException |
                 InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    public static void Init() {
        customParticleList.add(BaseSummonParticle.class);
        customParticleList.add(BaseSummonMagicParticle.class);
        customParticleList.add(BaseSummonMagicCircleParticle.class);
        customParticleList.add(DrawCircleSummonParticle.class);
        customParticleList.add(BaseAttackParticle.class);
    }

    public static List<Particle> spawnlistParticle(ParticleEffect parameters, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
        return spawnlistParticle(parameters, false, false, x, y, z, velocityX, velocityY, velocityZ);
    }

    //单粒子渲染
    public static List<Particle> spawnlistParticle(ParticleEffect parameters, boolean alwaysSpawn, boolean canSpawnOnMinimal, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
        List<Particle> list = new ArrayList<>();
        Particle particle = spawnParticle(parameters, alwaysSpawn, canSpawnOnMinimal, x, y, z, velocityX, velocityY, velocityZ);
        list.add(particle);
        return list;
    }

    //渲染自定义粒子
    public static List<Particle> spawnCustomlistParticle(ParticleEffect parameters, double x, double y, double z) {
        return spawnCustomlistParticle(parameters, false, false, x, y, z, 0, 0, 0);
    }

    public static List<Particle> spawnCustomlistParticle(ParticleEffect parameters, boolean alwaysSpawn, boolean canSpawnOnMinimal,
                                                         double x, double y, double z,
                                                         double velocityX, double velocityY, double velocityZ) {
        return spawnCustomlistParticle(parameters, alwaysSpawn, canSpawnOnMinimal, x, y, z, velocityX, velocityY, velocityZ, 0, 0.1f, 20);
    }

    public static List<Particle> spawnCustomlistParticle(ParticleEffect parameters, boolean alwaysSpawn, boolean canSpawnOnMinimal,
                                                         double x, double y, double z,
                                                         double velocityX, double velocityY, double velocityZ, float anglespeed,
                                                         float scale, int maxage) {
        return spawnCustomlistParticle(parameters, alwaysSpawn, canSpawnOnMinimal, x, y, z, velocityX, velocityY, velocityZ, anglespeed, scale, maxage, 1, 1, 1, 1);
    }

    public static List<Particle> spawnCustomlistParticle(ParticleEffect parameters, boolean alwaysSpawn, boolean canSpawnOnMinimal,
                                                         double x, double y, double z,
                                                         double velocityX, double velocityY, double velocityZ, float anglespeed,
                                                         float scale, int maxage, float red, float green, float blue, float alpha) {
        List<Particle> list = new ArrayList<>();
        Particle particle = spawnParticle(parameters, alwaysSpawn, canSpawnOnMinimal, x, y, z, velocityX, velocityY, velocityZ);
        if (particle instanceof CustomBaseParticle baseParticle) {
            baseParticle.setAnglespeed(anglespeed);
            baseParticle.setScale(scale);
            baseParticle.setMaxAge(maxage);
            baseParticle.setColor(red, green, blue);
            baseParticle.setColorAlpha(alpha);
        }
        list.add(particle);
        return list;
    }

    //渲染自定义方向粒子
    public static List<Particle> spawnCustomDirectionlistParticle(ParticleEffect parameters, double x, double y, double z) {
        return spawnCustomDirectionlistParticle(parameters, false, false, x, y, z, 0, 0, 0, 20, new Vec3d(x, y + 1, z), 0, false);
    }

    public static List<Particle> spawnCustomDirectionlistParticle(ParticleEffect parameters, double x, double y, double z, int maxage,
                                                                  Vec3d target, float speedangleself, boolean DirectionalLock) {
        return spawnCustomDirectionlistParticle(parameters, false, false, x, y, z, 0, 0, 0, maxage, target, speedangleself, DirectionalLock);
    }

    public static List<Particle> spawnCustomDirectionlistParticle(ParticleEffect parameters, boolean alwaysSpawn, boolean canSpawnOnMinimal,
                                                                  double x, double y, double z,
                                                                  double velocityX, double velocityY, double velocityZ, int maxage,
                                                                  Vec3d target, float speedangleself, boolean DirectionalLock) {
        return spawnCustomDirectionlistParticle(parameters, alwaysSpawn, canSpawnOnMinimal, x, y, z, velocityX, velocityY, velocityZ, 0, 0.1f, maxage, target, speedangleself, DirectionalLock);
    }

    public static List<Particle> spawnCustomDirectionlistParticle(ParticleEffect parameters, boolean alwaysSpawn, boolean canSpawnOnMinimal,
                                                                  double x, double y, double z,
                                                                  double velocityX, double velocityY, double velocityZ, float anglespeed,
                                                                  float scale, int maxage,
                                                                  Vec3d target, float speedangleself, boolean DirectionalLock) {
        return spawnCustomDirectionlistParticle(parameters, alwaysSpawn, canSpawnOnMinimal, x, y, z, velocityX, velocityY, velocityZ, anglespeed, scale, maxage, 1, 1, 1, 1, target, speedangleself, DirectionalLock);
    }

    public static List<Particle> spawnCustomDirectionlistParticle(ParticleEffect parameters, boolean alwaysSpawn, boolean canSpawnOnMinimal,
                                                                  double x, double y, double z,
                                                                  double velocityX, double velocityY, double velocityZ, float anglespeed,
                                                                  float scale, int maxage, float red, float green, float blue, float alpha,
                                                                  Vec3d target, float speedangleself, boolean DirectionalLock) {
        List<Particle> list = new ArrayList<>();
        Particle particle = spawnParticle(parameters, alwaysSpawn, canSpawnOnMinimal, x, y, z, velocityX, velocityY, velocityZ);
        if (particle instanceof CustomDirectionBaseParticle baseParticle) {
            baseParticle.setAnglespeed(anglespeed);
            baseParticle.setScale(scale);
            baseParticle.setMaxAge(maxage);
            baseParticle.setColor(red, green, blue);
            baseParticle.setColorAlpha(alpha);
            baseParticle.setTarget(target);
            baseParticle.setSpeedangleself(speedangleself);
            baseParticle.setDirectionalLock(DirectionalLock);
            CustomDirectionBaseParticle particle2 = (CustomDirectionBaseParticle) spawnParticle(parameters, alwaysSpawn, canSpawnOnMinimal, x, y, z, velocityX, velocityY, velocityZ);
            assert particle2 != null;
            particle2.setAnglespeed(anglespeed);
            particle2.setScale(scale);
            particle2.setMaxAge(maxage);
            particle2.setColor(red, green, blue);
            particle2.setColorAlpha(alpha);
            if (DirectionalLock) particle2.setTarget(new Vec3d(-target.x, -target.y, -target.z));
            else particle2.setTarget(new Vec3d(2 * x - target.x, 2 * y - target.y, 2 * z - target.z));
            particle2.setSpeedangleself(-speedangleself);
            particle2.setDirectionalLock(DirectionalLock);
            list.add(particle2);
        } else if (particle instanceof CustomBaseParticle baseParticle) {
            baseParticle.setAnglespeed(anglespeed);
            baseParticle.setScale(scale);
            baseParticle.setMaxAge(maxage);
            baseParticle.setColor(red, green, blue);
            baseParticle.setColorAlpha(alpha);
        }
        list.add(particle);
        return list;
    }

    //生成粒子
    @Nullable
    public static Particle spawnParticle(ParticleEffect parameters, boolean alwaysSpawn, boolean canSpawnOnMinimal, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
        Camera camera = MinecraftClient.getInstance().gameRenderer.getCamera();
        if (MinecraftClient.getInstance() == null || !camera.isReady() || MinecraftClient.getInstance().particleManager == null) {
            return null;
        }
        ParticlesMode particlesMode = getRandomParticleSpawnChance(canSpawnOnMinimal);
        if (alwaysSpawn) {
            return MinecraftClient.getInstance().particleManager.addParticle(parameters, x, y, z, velocityX, velocityY, velocityZ);
        }
        if (camera.getPos().squaredDistanceTo(x, y, z) > 1024.0) {
            return null;
        }
        if (particlesMode == ParticlesMode.MINIMAL) {
            return null;
        }
        return MinecraftClient.getInstance().particleManager.addParticle(parameters, x, y, z, velocityX, velocityY, velocityZ);
    }

    //获取粒子渲染密度，当粒子为稀少时候是否渲染
    public static ParticlesMode getRandomParticleSpawnChance(boolean canSpawnOnMinimal) {
        ParticlesMode particlesMode = MinecraftClient.getInstance().options.particles;
        assert MinecraftClient.getInstance().world != null;
        if (canSpawnOnMinimal && particlesMode == ParticlesMode.MINIMAL && MinecraftClient.getInstance().world.random.nextInt(10) == 0) {
            particlesMode = ParticlesMode.DECREASED;
        }
        if (particlesMode == ParticlesMode.DECREASED && MinecraftClient.getInstance().world.random.nextInt(3) == 0) {
            particlesMode = ParticlesMode.MINIMAL;
        }
        return particlesMode;
    }


}
